package me.eachann.session

import android.util.Log
import androidx.annotation.IntRange
import androidx.annotation.NonNull
import java.io.Serializable
import java.lang.IllegalArgumentException
import java.util.*
import java.util.concurrent.ConcurrentHashMap


object SessionManager {
    private var mSessionManager: ISessionManager? = null
    //如果读取同一session超过默认次数,则增加缓存,提升读取速度
    private var mDefaultHighFrequency = 2
    //当前读取频次
    private val mCurrentFrequency = ConcurrentHashMap<String, Int>()
    private val mCache = ConcurrentHashMap<String, Serializable>()
    /**
     * 超过指定访问次数，自动加入缓存,提升读取性能
     */
    fun setHighFrequency(@IntRange(from = 1) count: Int) {
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        if (count < 1) throw IllegalArgumentException("High Frequency must >0")
        mDefaultHighFrequency = count
    }

    fun init(@NonNull sessionManager: ISessionManager) {
        this.mSessionManager = sessionManager
    }

    private fun ensureManager(): Boolean {
        return (mSessionManager == null)
    }

    fun isExist(cls: Class<*>): Boolean {
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        return getSession<Class<*>>(cls) != null
    }

    fun remove(cls: Class<*>) {
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        mSessionManager?.remove(cls)
        mCache.remove(cls.simpleName)
        mCurrentFrequency.remove(cls.simpleName)
    }

    fun clearAll() {
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        mSessionManager?.clearAll()
        mCache.clear()
        mCurrentFrequency.clear()
    }

    @Suppress("UNCHECKED_CAST")
    fun <T : Serializable> getSession(cls: Class<*>): T? {
//        val startTime = System.nanoTime()
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        var session: T? = null
        mCurrentFrequency[cls.simpleName] = mCurrentFrequency[cls.simpleName]?.plus(1) ?: 1
        mCurrentFrequency[cls.simpleName]?.let {
            if (it < mDefaultHighFrequency) {
                session = mSessionManager?.getSession(cls)
            } else {
                val tempSession: Serializable? =
                    mCache[cls.simpleName] ?: mSessionManager?.getSession(cls)
                tempSession?.run {
                    mCache[cls.simpleName] = this
                }
                session = tempSession as T?
            }
        }
//        Log.w("getSession", (System.nanoTime() - startTime).toString())
        return session
    }

    fun <T : Serializable> setSession(session: T) {
        if (ensureManager()) {
            throw IllegalArgumentException("init method should be called first")
        }
        mCache.remove(session.javaClass.simpleName)
        mSessionManager?.setSession(session)
    }

    private val mSessionStateChangedListeners: MutableList<SessionStateChangedListener> =
        ArrayList()

    /**
     * 添加Session状态改变通知，在不用时候记得移除掉，避免内存泄漏
     */
    fun addSessionStateChangedListener(listener: SessionStateChangedListener) {
        mSessionStateChangedListeners.add(listener)
    }

    /**
     * 移除Session状态改变通知
     */
    fun removeSessionStateChangedListener(listener: SessionStateChangedListener) {
        mSessionStateChangedListeners.remove(listener)
    }

    /**
     * 移除Session状态改变通知所有监听
     */
    fun clearListeners() {
        mSessionStateChangedListeners.clear()
    }

    fun notifyOnSessionStateChanged(session: Any?) {
        for (listener in mSessionStateChangedListeners) {
            listener.onSessionStateChanged(session = session)
        }
    }
}